#pragma once

#include <iostream>
#include <memory>
#include <mutex>
#include <cassert>
#include <unordered_map>
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include "google/protobuf/map.h"

namespace bitmq
{
    // 1. 定义队列描述数据类
    struct MsgQueue
    {
        using ptr = std::shared_ptr<MsgQueue>;
        MsgQueue()
        {}

        MsgQueue(const std::string& qname, bool qdurable, 
            bool qexclusive, bool qauto_delete,
            google::protobuf::Map<std::string, std::string>& qargs)
                : name(qname)
                , durable(qdurable)
                , exclusive(qexclusive)
                , auto_delete(qauto_delete)
                , args(qargs)
        {}
        
        //解析str_args字符串，将结果存储到成员中（反序列化)
        void setArgs(const std::string& str_args)
        {
            std::vector<std::string> sub_args;
            size_t ret = bitmq::StringHelper::splite(str_args, "&", sub_args);
            for (auto& str : sub_args)
            {
                size_t pos = str.find('=');
                std::string key = str.substr(0, pos);
                std::string value = str.substr(pos+1);
                args.insert({key, value});
            }
        }

        //将args中的内容进行序列化，返回字符串
        std::string getArgs()
        {
            std::string ret;
            for (auto& [k, v] : args)
            {
                ret += k + '=' + v;
                ret += '&';
            }
            if (ret.size() != 0)
                ret.pop_back();
            return ret;
        }

        std::string name;  // 1）队列名称
        bool durable;      // 2）是否持久化标志
        bool exclusive;    // 3）是否独占标志
        bool auto_delete;  // 4）是否自动删除标志
        google::protobuf::Map<std::string, std::string> args;   // 5）其他参数
    };

    // 2. 定义队列数据持久化类（数据持久化的 sqlite3 数据库中）
    class MsgQueueMapper
    {
    public:
        MsgQueueMapper(const std::string& dbfile)
            : _sql_helper(dbfile)
        {
            std::string path = bitmq::FileHelper::parentDirectory(dbfile);
            bitmq::FileHelper::createDirectory(path);
            assert(_sql_helper.open());
            createTable();
        }

        void createTable()   // 1）创建队列数据表
        {
            std::string sql = "create table if not exists queue_table(name varchar(32) primary key, durable int, \
                exclusive int, auto_delete int, args varchar(128));";
            assert(_sql_helper.exec(sql, nullptr, nullptr));
        }

        void removeTable()   // 2）删除队列数据表
        {
            std::string sql = "drop table if exists queue_table";
            assert(_sql_helper.exec(sql, nullptr, nullptr));
        }

        void insert(MsgQueue::ptr& queue)   // 3）新增队列数据
        {
            std::stringstream sql;
            sql << "insert into queue_table values(";
            sql << "'" << queue->name << "', ";
            sql << queue->durable << ", ";
            sql << queue->exclusive << ", ";
            sql << queue->auto_delete << ", ";
            sql <<  "'" << queue->getArgs() << "');";
            _sql_helper.exec(sql.str(), nullptr, nullptr);
        }

        void remove(const std::string& name) // 4）移除队列数据
        {
            std::string sql = "delete from queue_table where name = '";
            sql += name + "';";
            _sql_helper.exec(sql, nullptr, nullptr);
        }

        using QueueMap = std::unordered_map<std::string, MsgQueue::ptr>;
        QueueMap recovery()   // 5）查询所有队列数据
        {
            std::string sql = "select name, durable, exclusive, auto_delete, args from queue_table";
            QueueMap result;
            _sql_helper.exec(sql, selectAllCallback, &result);
            return result;
        }

    private:
        static int selectAllCallback(void* arg, int numCol, char** row, char** fields)
        {
            QueueMap* result = (QueueMap*)arg;
            auto exp = std::make_shared<MsgQueue>();
            exp->name = row[0];
            exp->durable = (bool)std::stoi(row[1]);
            exp->exclusive = (bool)std::stoi(row[2]);
            exp->auto_delete = (bool)std::stoi(row[3]);
            if (row[4])
                exp->setArgs(row[4]);
            result->insert({exp->name, exp});
            return 0;
        }

    private:
        bitmq::SqliteHelper _sql_helper;
    };

    // 3. 定义队列数据管理类
    class MsgQueueManager
    {
    public:
        using ptr = std::shared_ptr<MsgQueueManager>;
        using QueueMap = std::unordered_map<std::string, MsgQueue::ptr>;

        MsgQueueManager(const std::string& dbfile)
        : _mapper(dbfile)
        {
            //恢复所有数据
            _msg_queues = _mapper.recovery();
        }

        // 1）创建队列，并添加管理（存在则 OK，不存在则创建）
        bool declareQueue(const std::string& name, bool durable, bool exclusive, 
            bool auto_delete, google::protobuf::Map<std::string, std::string> args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if (it != _msg_queues.end())
                return true;
            MsgQueue::ptr mqp = std::make_shared<MsgQueue>();
            mqp->name = name;
            mqp->durable = durable;
            mqp->exclusive = exclusive;
            mqp->auto_delete = auto_delete;
            mqp->args = args;
            if (durable == true)
                _mapper.insert(mqp);
            _msg_queues.insert({name, mqp});
            return true;
        }

        // 2）删除队列
        void deleteQueue(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if (it == _msg_queues.end())
                return;
            if (it->second->durable == true)
                _mapper.remove(name);
            _msg_queues.erase(name);
        }

        // 3）获取指定队列
        MsgQueue::ptr selectQueue(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if (it == _msg_queues.end())
                return {};
            return it->second;       
        }

        // 4）获取所有队列
        QueueMap getAllQueues() 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues;
        }

        // 5）判断指定队列是否存在
        bool exists(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if (it == _msg_queues.end())
                return false;
            return true;  
        }

        // 6）获取队列数量
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues.size();
        }

        // 7）销毁所有队列数据
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _msg_queues.clear();
        }
    
    private:
        std::mutex _mutex;
        MsgQueueMapper _mapper;
        QueueMap _msg_queues;
    };
}